using System;
using System.ComponentModel;
using System.Drawing;
using System.Drawing.Drawing2D;
using System.Drawing.Text;
using System.Threading;
using System.Windows.Forms;

namespace HslControls
{
	/// <summary>
	/// 仪表盘控件对象
	/// </summary>
	[Description("新的仪表盘控件，外观像汽车的仪表盘，支持设置范围，单位，指针颜色")]
	public class HslGaugeChart : UserControl
	{
		private Color color_gauge_border = Color.DimGray;

		private Pen pen_gauge_border = new Pen(Color.DimGray);

		private Brush pen_gauge_mark = new SolidBrush(Color.DimGray);

		private Brush foreBrush = new SolidBrush(Color.DodgerBlue);

		private Color color_gauge_pointer = Color.Tomato;

		private Brush brush_gauge_pointer = null;

		private double value_start = 0.0;

		private double value_max = 100.0;

		private double value_current = 0.0;

		private double value_alarm_max = 80.0;

		private double value_alarm_min = 20.0;

		private Pen pen_gauge_alarm = null;

		private int m_version = 0;

		private double value_paint = 0.0;

		private object hybirdLock;

		private Action m_UpdateAction;

		private int segment_count = 10;

		private StringFormat sf = null;

		private string value_unit_text = string.Empty;

		private bool text_under_pointer = true;

		private bool isBigSemiCircle = false;

		/// <summary> 
		/// 必需的设计器变量。
		/// </summary>
		private IContainer components = null;

		/// <summary>
		/// 获取或设置控件的背景色
		/// </summary>
		[Browsable(true)]
		[Description("获取或设置控件的背景色")]
		[Category("HslControls")]
		[DefaultValue(typeof(Color), "Transparent")]
		[EditorBrowsable(EditorBrowsableState.Always)]
		public override Color BackColor
		{
			get
			{
				return base.BackColor;
			}
			set
			{
				base.BackColor = value;
			}
		}

		/// <summary>
		/// 获取或设置仪表盘的背景色
		/// </summary>
		[Browsable(true)]
		[Category("HslControls")]
		[Description("获取或设置仪表盘的背景色")]
		[DefaultValue(typeof(Color), "DimGray")]
		public Color GaugeBorder
		{
			get
			{
				return color_gauge_border;
			}
			set
			{
				pen_gauge_border?.Dispose();
				pen_gauge_border = new Pen(value);
				color_gauge_border = value;
				pen_gauge_mark.Dispose();
				pen_gauge_mark = new SolidBrush(value);
				Invalidate();
			}
		}

		/// <summary>
		/// 获取或设置指针的颜色
		/// </summary>
		[Browsable(true)]
		[Category("HslControls")]
		[Description("获取或设置仪表盘指针的颜色")]
		[DefaultValue(typeof(Color), "Tomato")]
		public Color PointerColor
		{
			get
			{
				return color_gauge_pointer;
			}
			set
			{
				brush_gauge_pointer?.Dispose();
				brush_gauge_pointer = new SolidBrush(value);
				color_gauge_pointer = value;
				Invalidate();
			}
		}

		/// <summary>
		/// 获取或设置数值的起始值，默认为0
		/// </summary>
		[Browsable(true)]
		[Category("HslControls")]
		[Description("获取或设置数值的起始值，默认为0")]
		[DefaultValue(0.0)]
		public double ValueStart
		{
			get
			{
				if (value_max <= value_start)
				{
					return value_start + 1.0;
				}
				return value_start;
			}
			set
			{
				value_start = value;
				Invalidate();
			}
		}

		/// <summary>
		/// 获取或设置数值的最大值，默认为100
		/// </summary>
		[Browsable(true)]
		[Category("HslControls")]
		[Description("获取或设置数值的最大值，默认为100")]
		[DefaultValue(100.0)]
		public double ValueMax
		{
			get
			{
				if (value_max <= value_start)
				{
					return value_start + 1.0;
				}
				return value_max;
			}
			set
			{
				value_max = value;
				Invalidate();
			}
		}

		/// <summary>
		/// 获取或设置数值的当前值，应该处于最小值和最大值之间
		/// </summary>
		[Browsable(true)]
		[Category("HslControls")]
		[Description("获取或设置数值的当前值，默认为0")]
		[DefaultValue(0.0)]
		public double Value
		{
			get
			{
				return value_current;
			}
			set
			{
				if (ValueStart <= value && value <= ValueMax && value != value_current)
				{
					value_current = value;
					int version = Interlocked.Increment(ref m_version);
					ThreadPool.QueueUserWorkItem(ThreadPoolUpdateProgress, version);
				}
			}
		}

		/// <summary>
		/// 获取或设置数值的上限报警值，设置为超过最大值则无上限报警
		/// </summary>
		[Browsable(true)]
		[Category("HslControls")]
		[Description("获取或设置数值的上限报警值，设置为超过最大值则无上限报警，默认为80")]
		[DefaultValue(80.0)]
		public double ValueAlarmMax
		{
			get
			{
				return value_alarm_max;
			}
			set
			{
				if (ValueStart <= value)
				{
					value_alarm_max = value;
					Invalidate();
				}
			}
		}

		/// <summary>
		/// 获取或设置数值的下限报警值，设置为超过最大值则无上限报警
		/// </summary>
		[Browsable(true)]
		[Category("HslControls")]
		[Description("获取或设置数值的下限报警值，设置为小于最小值则无下限报警，默认为20")]
		[DefaultValue(20.0)]
		public double ValueAlarmMin
		{
			get
			{
				return value_alarm_min;
			}
			set
			{
				if (value <= ValueMax)
				{
					value_alarm_min = value;
					Invalidate();
				}
			}
		}

		/// <summary>
		/// 获取或设置仪表盘的分割段数，最小为2，最大1000
		/// </summary>
		[Browsable(true)]
		[Category("HslControls")]
		[Description("获取或设置仪表盘的分割段数，最小为2，最大1000")]
		[DefaultValue(10)]
		public int SegmentCount
		{
			get
			{
				return segment_count;
			}
			set
			{
				if (value > 1 && value < 1000)
				{
					segment_count = value;
					Invalidate();
				}
			}
		}

		/// <summary>
		/// 获取或设置仪表盘的单位描述文本
		/// </summary>
		[Browsable(true)]
		[Category("HslControls")]
		[Description("获取或设置仪表盘的单位描述文本")]
		[DefaultValue("")]
		public string UnitText
		{
			get
			{
				return value_unit_text;
			}
			set
			{
				value_unit_text = value;
				Invalidate();
			}
		}

		/// <summary>
		/// 获取或设置文本是否是指针的下面
		/// </summary>
		[Browsable(true)]
		[Category("HslControls")]
		[Description("获取或设置文本是否是指针的下面")]
		[DefaultValue(true)]
		public bool IsTextUnderPointer
		{
			get
			{
				return text_under_pointer;
			}
			set
			{
				text_under_pointer = value;
				Invalidate();
			}
		}

		/// <summary>
		/// 通常情况，仪表盘不会大于半个圆，除非本属性设置为 True
		/// </summary>
		[Browsable(true)]
		[Category("HslControls")]
		[Description("通常情况，仪表盘不会大于半个圆，除非本属性设置为 True")]
		[DefaultValue(false)]
		public bool IsBigSemiCircle
		{
			get
			{
				return isBigSemiCircle;
			}
			set
			{
				isBigSemiCircle = value;
				Invalidate();
			}
		}

		/// <summary>
		/// 获取或设置控件的前景色
		/// </summary>
		[Category("HslControls")]
		[Description("获取或设置控件的前景色")]
		[DefaultValue(typeof(Color), "DodgerBlue")]
		public override Color ForeColor
		{
			get
			{
				return base.ForeColor;
			}
			set
			{
				base.ForeColor = value;
				foreBrush.Dispose();
				foreBrush = new SolidBrush(value);
				Invalidate();
			}
		}

		/// <summary>
		/// 实例化一个仪表盘控件
		/// </summary>
		public HslGaugeChart()
		{
			InitializeComponent();
			brush_gauge_pointer = new SolidBrush(color_gauge_pointer);
			sf = new StringFormat();
			sf.Alignment = StringAlignment.Center;
			sf.LineAlignment = StringAlignment.Center;
			pen_gauge_alarm = new Pen(Color.OrangeRed, 3f);
			pen_gauge_alarm.DashStyle = DashStyle.Custom;
			pen_gauge_alarm.DashPattern = new float[2]
			{
				5f,
				1f
			};
			hybirdLock = new object();
			m_UpdateAction = base.Invalidate;
			SetStyle(ControlStyles.UserPaint | ControlStyles.SupportsTransparentBackColor, value: true);
			SetStyle(ControlStyles.ResizeRedraw, value: true);
			SetStyle(ControlStyles.OptimizedDoubleBuffer, value: true);
			SetStyle(ControlStyles.AllPaintingInWmPaint, value: true);
			ForeColor = Color.DodgerBlue;
		}

		/// <summary>
		/// 重绘
		/// </summary>
		/// <param name="e">重绘的事件</param>
		protected override void OnPaint(PaintEventArgs e)
		{
			if (!Authorization.iashdiadasbdnajsdhjaf())
			{
				return;
			}
			Graphics g = e.Graphics;
			g.SmoothingMode = SmoothingMode.HighQuality;
			g.TextRenderingHint = TextRenderingHint.ClearTypeGridFit;
			CenterPoint setting = GetCenterPoint();
			if (setting == null)
			{
				return;
			}
			Point center = setting.Point;
			int radius = setting.Radius;
			float angle = Convert.ToSingle(setting.Angle);
			Rectangle circular = new Rectangle(-radius, -radius, 2 * radius, 2 * radius);
			Rectangle circular_larger = new Rectangle(-radius - 5, -radius - 5, 2 * radius + 10, 2 * radius + 10);
			Rectangle circular_mini = new Rectangle(-radius / 3, -radius / 3, 2 * radius / 3, 2 * radius / 3);
			g.TranslateTransform(center.X, center.Y);
			g.DrawArc(pen_gauge_border, circular_mini, 0f - angle, angle * 2f - 180f);
			g.DrawArc(pen_gauge_border, circular, angle - 180f, 180f - angle * 2f);
			g.DrawLine(pen_gauge_border, (int)((double)(-(radius / 3)) * Math.Cos((double)(angle / 180f) * Math.PI)), -(int)((double)(radius / 3) * Math.Sin((double)(angle / 180f) * Math.PI)), -(int)((double)(radius - 10 - Font.Height) * Math.Cos((double)(angle / 180f) * Math.PI)), -(int)((double)(radius - 10 - Font.Height) * Math.Sin((double)(angle / 180f) * Math.PI)));
			g.DrawLine(pen_gauge_border, (int)((double)(radius - 10 - Font.Height) * Math.Cos((double)(angle / 180f) * Math.PI)), -(int)((double)(radius - 10 - Font.Height) * Math.Sin((double)(angle / 180f) * Math.PI)), (int)((double)(radius / 3) * Math.Cos((double)(angle / 180f) * Math.PI)), -(int)((double)(radius / 3) * Math.Sin((double)(angle / 180f) * Math.PI)));
			g.RotateTransform(angle - 90f);
			int totle = segment_count;
			for (int i = 0; i <= totle; i++)
			{
				g.FillRectangle(rect: new Rectangle(-2, -radius, 3, 7), brush: pen_gauge_mark);
				g.DrawString(layoutRectangle: new Rectangle(-100, -radius + 7, 200, Font.Height + 3), s: (ValueStart + (ValueMax - ValueStart) * (double)i / (double)totle).ToString(), font: Font, brush: foreBrush, format: sf);
				g.RotateTransform((180f - 2f * angle) / (float)totle / 2f);
				if (i != totle)
				{
					g.DrawLine(pen_gauge_border, 0, -radius, 0, -radius + 3);
				}
				g.RotateTransform((180f - 2f * angle) / (float)totle / 2f);
			}
			g.RotateTransform((0f - (180f - 2f * angle)) / (float)totle);
			g.RotateTransform(angle - 90f);
			Rectangle text = new Rectangle(-200, -(radius * 2 / 3 - 3), 400, Font.Height + 3);
			if (IsTextUnderPointer)
			{
				g.DrawString(Value.ToString(), Font, foreBrush, text, sf);
				text.Offset(0, Font.Height);
				if (!string.IsNullOrEmpty(UnitText))
				{
					g.DrawString(UnitText, Font, foreBrush, text, sf);
				}
			}
			g.RotateTransform(angle - 90f);
			g.RotateTransform((float)((value_paint - ValueStart) / (ValueMax - ValueStart) * (double)(180f - 2f * angle)));
			g.FillEllipse(rect: new Rectangle(-5, -5, 10, 10), brush: brush_gauge_pointer);
			Point[] points = new Point[5]
			{
				new Point(5, 0),
				new Point(2, -radius + 40),
				new Point(0, -radius + 20),
				new Point(-2, -radius + 40),
				new Point(-5, 0)
			};
			g.FillPolygon(brush_gauge_pointer, points);
			g.RotateTransform((float)((0.0 - (value_paint - ValueStart)) / (ValueMax - ValueStart) * (double)(180f - 2f * angle)));
			g.RotateTransform(90f - angle);
			if (value_alarm_min > ValueStart && value_alarm_min <= ValueMax)
			{
				g.DrawArc(pen_gauge_alarm, circular_larger, angle - 180f, (float)((ValueAlarmMin - ValueStart) / (ValueMax - ValueStart) * (double)(180f - 2f * angle)));
			}
			if (value_alarm_max >= ValueStart && value_alarm_max < ValueMax)
			{
				float angle_max = (float)((value_alarm_max - ValueStart) / (ValueMax - ValueStart) * (double)(180f - 2f * angle));
				g.DrawArc(pen_gauge_alarm, circular_larger, -180f + angle + angle_max, 180f - 2f * angle - angle_max);
			}
			if (!IsTextUnderPointer)
			{
				g.DrawString(Value.ToString(), Font, foreBrush, text, sf);
				text.Offset(0, Font.Height);
				if (!string.IsNullOrEmpty(UnitText))
				{
					g.DrawString(UnitText, Font, foreBrush, text, sf);
				}
			}
			g.ResetTransform();
			base.OnPaint(e);
		}

		/// <summary>
		/// 获取中心点的坐标
		/// </summary>
		/// <returns>中心点对象</returns>
		private CenterPoint GetCenterPoint()
		{
			CenterPoint centerPoint = new CenterPoint();
			if (base.Height <= 35)
			{
				return null;
			}
			if (base.Width <= 20)
			{
				return null;
			}
			if (!IsBigSemiCircle)
			{
				centerPoint.Radius = base.Height - 30;
				if ((double)(base.Width - 40) / 2.0 > (double)centerPoint.Radius)
				{
					centerPoint.Angle = Math.Acos(1.0) * 180.0 / Math.PI;
				}
				else
				{
					centerPoint.Angle = Math.Acos((double)(base.Width - 40) / 2.0 / (double)(base.Height - 30)) * 180.0 / Math.PI;
				}
				centerPoint.Point = new Point(base.Width / 2, base.Height - 10);
				return centerPoint;
			}
			centerPoint.Radius = (base.Width - 40) / 2;
			if (base.Height - 30 < centerPoint.Radius)
			{
				centerPoint.Radius = base.Height - 30;
				centerPoint.Angle = Math.Acos(1.0) * 180.0 / Math.PI;
				centerPoint.Point = new Point(base.Width / 2, base.Height - 10);
				return centerPoint;
			}
			int left = base.Height - 30 - centerPoint.Radius;
			if (left > centerPoint.Radius)
			{
				left = centerPoint.Radius;
			}
			centerPoint.Angle = (0.0 - Math.Asin((double)left * 1.0 / (double)centerPoint.Radius)) * 180.0 / Math.PI;
			centerPoint.Point = new Point(base.Width / 2, centerPoint.Radius + 20);
			return centerPoint;
		}

		private void ThreadPoolUpdateProgress(object obj)
		{
			try
			{
				int version = (int)obj;
				if (value_paint == value_current)
				{
					return;
				}
				double m_speed = Math.Abs(value_paint - value_current) / 10.0;
				if (m_speed == 0.0)
				{
					m_speed = 1.0;
				}
				while (value_paint != value_current)
				{
					Thread.Sleep(17);
					if (version != m_version)
					{
						break;
					}
					lock (hybirdLock)
					{
						double newActual = 0.0;
						if (value_paint > value_current)
						{
							double offect2 = value_paint - value_current;
							if (offect2 > m_speed)
							{
								offect2 = m_speed;
							}
							newActual = value_paint - offect2;
						}
						else
						{
							double offect = value_current - value_paint;
							if (offect > m_speed)
							{
								offect = m_speed;
							}
							newActual = value_paint + offect;
						}
						value_paint = newActual;
					}
					if (version == m_version)
					{
						if (base.IsHandleCreated)
						{
							Invoke(m_UpdateAction);
						}
						continue;
					}
					break;
				}
			}
			catch (Exception)
			{
			}
		}

		/// <summary> 
		/// 清理所有正在使用的资源。
		/// </summary>
		/// <param name="disposing">如果应释放托管资源，为 true；否则为 false。</param>
		protected override void Dispose(bool disposing)
		{
			if (disposing && components != null)
			{
				components.Dispose();
			}
			base.Dispose(disposing);
		}

		/// <summary> 
		/// 设计器支持所需的方法 - 不要修改
		/// 使用代码编辑器修改此方法的内容。
		/// </summary>
		private void InitializeComponent()
		{
			SuspendLayout();
			base.AutoScaleMode = System.Windows.Forms.AutoScaleMode.None;
			BackColor = System.Drawing.Color.Transparent;
			base.Name = "HslGaugeChart";
			ResumeLayout(false);
		}
	}
}
